#ifndef _INCLUDED_CLASS_ENCODER_H_
#define _INCLUDED_CLASS_ENCODER_H_

//=======================================================================//
//= Include files.													    =//
//=======================================================================//
#include <wx/image.h>
#include <wx/string.h>
#include <wx/image.h>
#include <wx/xml/xml.h>
#include <wx/list.h>

//=======================================================================//
//= Marco declare.                                                      =//
//=======================================================================//
#define CFG_XML_NODE_NAME_ENCORDER			(wxT("Encoder"))
#define CFG_XML_NODE_NAME_ENC_SCAN			(wxT("ScanOrder"))
#define CFG_XML_NODE_NAME_ENC_DATA_DIR		(wxT("DataDirection"))
#define CFG_XML_NODE_NAME_ENC_BIT_ORDER		(wxT("BitOrder"))
#define CFG_XML_NODE_ATTR_VALUE				(wxT("value"))

//=======================================================================//
//= Global variable declare.										    =//
//=======================================================================//
extern const wxString			ScanOrderItems[];
extern const wxString			DataDirectionItems[];
extern const wxString			BitOrderItems[];
extern const size_t             SCAN_ORDER_ITEMS_COUNT;
extern const size_t             DATA_DIRECTION_ITEMS_COUNT;
extern const size_t             BIT_ORDER_ITEMS_COUNT;

extern const wxString			CONFIG_FILE_PATH;
extern const wxString			CONFIG_FILE_NAME;
extern const wxString			STARTUP_FILE_NAME;

//=======================================================================//
//= Data type declare.                                                  =//
//=======================================================================//
typedef enum
{
	HORIZONTAL_DATA,
	VERTICAL_DATA,
}DATA_DIRECTION;

typedef enum
{
	HORIZONTAL_FIRST,
	VERTICAL_FIRST,
}SCAN_ORDER;

typedef enum
{
	LOW_BIT_START,
	HIGH_BIT_START,
}BIT_ORDER;

class RasterizedMonoImage;

typedef wxVector<uint8_t>				RasterizedMonoData;
typedef wxVector<RasterizedMonoImage>	RasterizedDataArray;

//=======================================================================//
//= Class declare.                                                      =//
//=======================================================================//
class EncoderConfiguration
{
private:
	DATA_DIRECTION				m_eDataDirection;
	SCAN_ORDER					m_eScanOrder;
	BIT_ORDER					m_eBitOrder;
public:
								EncoderConfiguration(void);
								EncoderConfiguration(const wxXmlNode* pclsXmlNode);
								EncoderConfiguration(const EncoderConfiguration& clsSource);
	wxXmlNode*					CreateXmlNode(void);
	bool						FromXmlNode(const wxXmlNode* pclsXmlNode);
	DATA_DIRECTION				GetDataDirection(void) const				{return m_eDataDirection;}
	SCAN_ORDER					GetScanOrder(void) const					{return m_eScanOrder;}
	BIT_ORDER					GetBitOrder(void) const						{return m_eBitOrder;}
	void						SetDataDirection(DATA_DIRECTION eNewDataDirection){m_eDataDirection = eNewDataDirection;}
	void						SetScanOrder(SCAN_ORDER eNewScanOrder)		{m_eScanOrder = eNewScanOrder;}
	void						SetBitOrder(BIT_ORDER eNewBitOrder)			{m_eBitOrder = eNewBitOrder;}
	EncoderConfiguration&		operator=(const EncoderConfiguration& clsObject);
};

class RasterizedMonoImage
{
private:
	RasterizedMonoData			m_clsData;
	wxString					m_strComment;

public:
								RasterizedMonoImage(void)					{/* Do nothing. */}
								RasterizedMonoImage(const RasterizedMonoData& clsData){m_clsData = clsData;}
								RasterizedMonoImage(const RasterizedMonoImage& clsSource){m_clsData = clsSource.Data();}
	const RasterizedMonoData	Data(void) const 							{return m_clsData;}
	RasterizedMonoData			Data(void) 		 							{return m_clsData;}
	uint8_t						Item(size_t sIndex) const					{return (sIndex<m_clsData.size())?(m_clsData.at(sIndex)):(0);}
	size_t						Size(void) const							{return m_clsData.size();}
	virtual void				SetData(const RasterizedMonoData& clsNewData){m_clsData = clsNewData;}
	void						Append(uint8_t uiData)						{m_clsData.push_back(uiData);}
	virtual void				Clear(void);
	virtual void				SetComment(const wxString& cstrCommentText)	{m_strComment = cstrCommentText;}
	virtual const wxString&		GetComment(void) const						{return m_strComment;}
};

class RasterizedMonoChar
: public RasterizedMonoImage
{
private:
	size_t						m_sIndex;
	wxUniChar					m_cChar;

public:
								RasterizedMonoChar(const wxUniChar wcNewChar = '\0');
								RasterizedMonoChar(size_t sIndex, const wxUniChar wcNewChar = '\0');
								RasterizedMonoChar(const RasterizedMonoChar& clsSource);
	void						SetChar(const wxUniChar wcNewChar);
	void						SetIndex(size_t sIndex);
	const wxUniChar&			GetChar(void) const							{return m_cChar;}
	size_t						GetIndex(void) const						{return m_sIndex;}
	virtual void				SetComment(const wxString& cstrCommentText)	{/* Comment text automatically generated, do nothing. */;}
};

class Encoder
{
private:
	EncoderConfiguration		m_clsEncodeConfig;

	void						_initialize(void);
	uint8_t						_getByte(const wxImage& clsImage, int iLineIdx, int iColumnIdx, DATA_DIRECTION eByteDriect, BIT_ORDER eNewStartBitType);
	int							_getPixelValue(const wxImage& clsImage, int iCoodX, int iCoodY);

public:
								Encoder(void);
								~Encoder(void);
	void						SetByteEndianType(BIT_ORDER eNewStartBitType){m_clsEncodeConfig.SetBitOrder(eNewStartBitType);}
	void						SetByteDirection(DATA_DIRECTION eNewByteDirection){m_clsEncodeConfig.SetDataDirection(eNewByteDirection);}
	void						SetEncodeOrder(SCAN_ORDER eNewOrder)		{m_clsEncodeConfig.SetScanOrder(eNewOrder);}
	BIT_ORDER					GetEndianType(void)							{return m_clsEncodeConfig.GetBitOrder();}
	DATA_DIRECTION				GetByteDirection(void)						{return m_clsEncodeConfig.GetDataDirection();}
	SCAN_ORDER					GetEncodeOrder(void)						{return m_clsEncodeConfig.GetScanOrder();}
	void						SetConfig(const EncoderConfiguration& clsNewEncoderSettings){m_clsEncodeConfig = clsNewEncoderSettings;}
	const EncoderConfiguration&	GetConfig(void) const						{return m_clsEncodeConfig;}
	bool						Encode(const wxImage& clsImage, RasterizedMonoImage& clsRasterizedData);
};

#endif // _INCLUDED_CLASS_ENCODER_H_
